package com.cube.share.base.config;

import cn.hutool.core.util.StrUtil;
import com.cube.share.base.templates.ApiResult;
import com.cube.share.base.templates.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.TypeMismatchException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author litb
 * @date 2021/3/11 15:21
 * @description 全局异常处理器
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(CustomException.class)
    public ApiResult<Void> customExceptionHandler(CustomException ce) {
        ce.printStackTrace();
        return ApiResult.error(ce.getMessage());
    }

    @ExceptionHandler(BindException.class)
    public ApiResult<Void> handleBindException(BindException e) {
        final BindingResult bindingResult = e.getBindingResult();
        final List<FieldError> fieldErrorList = bindingResult.getFieldErrors();
        final String message;
        if (CollectionUtils.isEmpty(fieldErrorList)) {
            message = "参数不符合规范";
        } else {
            message =
                    fieldErrorList.stream()
                            .map(DefaultMessageSourceResolvable::getDefaultMessage)
                            .filter(StrUtil::isNotBlank)
                            .distinct()
                            .collect(Collectors.joining(",并且"));
        }
        return ApiResult.error(message);
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public ApiResult<Void> handleConstraintViolationException(ConstraintViolationException ce) {
        Set<ConstraintViolation<?>> constraintViolationSet = ce.getConstraintViolations();
        //TODO:待实现
        return ApiResult.error("异常");
    }

    @ExceptionHandler(HttpMessageConversionException.class)
    public ApiResult<Void> handleHttpMessageConversionException(HttpMessageConversionException hce) {
        //RequestBody注释的参数类型不匹配
        return ApiResult.error("参数转换异常");
    }

    @ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
    public ApiResult<Void> handleHttpMediaTypeNotAcceptableException(HttpMediaTypeNotAcceptableException hte) {
        //TODO:待实现
        return ApiResult.error("不支持的请求头");
    }

    @ExceptionHandler(TypeMismatchException.class)
    public ApiResult<TypeMismatchException> handleTypeMismatchException(TypeMismatchException tme) {
        //非RequestBody注释入参,参数放在query里或者body里
        return ApiResult.error("参数类型匹配失败");
    }

    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public ApiResult<HttpMediaTypeNotSupportedException> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException hte) {
        //使用RequestBody接收入参
        return ApiResult.error("请检查Content-Type是否正确");
    }

    @ExceptionHandler(Exception.class)
    public ApiResult<Void> exceptionHandler(Exception e) {
        log.error("系统异常,error_msg = {}", e.getMessage());
        return ApiResult.error("系统异常!");
    }
}
